package com.uxwine.alarm.main;

import java.sql.Date;

import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.text.format.DateFormat;
import android.view.View;
import android.widget.Toast;

import com.uxwine.alarm.AlarmService;
import com.uxwine.alarm.R;
import com.uxwine.alarm.R.drawable;
import com.uxwine.audio.RingManager;
import com.uxwine.view.t.DialView;
import com.uxwine.view.t.DialViewAdapter;
import com.uxwine.view.t.TimeView;

public class AlarmBuilder {
	
	private Context mCtx;
	private MHandler mHandler;
	private DialView mDial;
	private TimeView mSpan;
	
	private RingManager mRing;
	
	/**adapter of time span*/
	private TSAdpater mTVAdpater;
	
	/**adapters of dial view when setting time*/
	private DialViewAdapter[] mDVAdapters;
	
	/**handle click event of dial view*/
	private OnDVClicked mOnDVClicked;
	
	/**handle click event of time span*/
	private MTVClickedListener mOnTVClicked;
	
	/**current alarm*/
	private Alarm mAlarm;
	
	/**backup alarm*/
	private Alarm mBkAlarm;
	
	private static final int STEP_CYCLE 		= 0;
	private static final int STEP_CYCLE_SELF 	= 1;
	private static final int STEP_TIME			= 2;
	private static final int STEP_SOUND			= 3;
	private int mnStep = STEP_CYCLE;
	
	private static final int MSG_PLAYRING = 1;
	
 	public AlarmBuilder(Context context)
	{
		mCtx = context;
		mTVAdpater = new TSAdpater();
		mOnTVClicked = new MTVClickedListener();
		mHandler = new MHandler();
		mRing = new RingManager(mCtx);
	}
	
	public void init(DialView d, TimeView t)
	{
		mDial = d;
		mSpan = t;
	}
	
	public AlarmBuilder build()
	{
		if(mAlarm != null)
		{
			Timer t = mTVAdpater.getTimer();
			mAlarm.setTime(t.getTime());
		}
		return this;
	}
	
	public AlarmBuilder setName(String name)
	{
		mAlarm.setName(name);
		return this;
	}
	
	public Alarm getAlarm()
	{
		return mAlarm;
	}
	
	public void save()
	{
		Alarm a = getAlarm();
		DBAlarms db = new DBAlarms(mCtx, true);
		if(a.getId() > 0)
			db.update(a);
		else
			db.put(a);
    	db.close();
       	
    	//Toast.makeText(mCtx, DateFormat.format("yyyy-MM-dd kk:mm", a.getTime()), Toast.LENGTH_LONG).show();
    	AlarmService.startAlarm(mCtx, a);
	}
	
	public AlarmBuilder create()
	{
		mBkAlarm = null;
		mAlarm = null;
		update();
		return this;
	}
	
	public AlarmBuilder edit(Alarm alarm)
	{
		if(null == alarm)
		{
			throw new NullPointerException();
		}
		
		mAlarm = alarm;
		
		mBkAlarm = new Alarm();
		mBkAlarm.copy(mAlarm);
		
		update();
		
		return this;
	}
	
	public AlarmBuilder reset()
	{
		Toast.makeText(mCtx, "Alarm has been reset!", Toast.LENGTH_SHORT).show();
		
		return create();
//		if(null == mBkAlarm)
//			return create();
//		else 
//			return edit(mBkAlarm);
	}
	
	public AlarmBuilder cycle()
	{
		Toast.makeText(mCtx, "Alarm has been cycled!", Toast.LENGTH_SHORT).show();
		update();
		return this;
	}
	
	public void show()
	{
		if(null == mAlarm)
		{
			throw new NullPointerException();
		}
		stop();
		showCycle();
	}
	
	public void stop()
	{
		mRing.stop();
	}
	
	private void update()
	{
		Timer t = initTimer();
		mTVAdpater.setTimer(t);
	}	
	
	private Timer initTimer()
	{
		Timer t = new Timer();
		
		if(null == mAlarm) //load from current time
		{
			mAlarm = new Alarm();
			
			t.init();
			mAlarm.setTime(t.getTime());
		}
		else			   //load from alarm
		{
			t.init(mAlarm.getTime());
		}
		return t;
	}
	
	/**step 1*/
	private void showCycle()
	{			
		//set step
		mnStep = STEP_CYCLE;
		
		//show time span
		mTVAdpater.setStates(null);
		mSpan.setOnTimeViewClikedListener(null);
		mSpan.setAdapter(mTVAdpater);
		mSpan.setShowMarker(false);
		mTVAdpater.notifyDataChanged();
		
		//show dial view
		mOnDVClicked = new OnDVClicked();
		mDial.setOnDialClickListener(mOnDVClicked);
		mDial.setOnDialMarkListener(mOnDVClicked);
		
		DialViewAdapter dv = getDialViewAdapter(mnStep);
		mDial.setAdpater(dv);	
		dv.notifyDataChanged();
	}	
	
	/**step 2*/
	private void showTimer()
	{		
		mnStep = STEP_TIME;
		int cycle = mAlarm.getCycle();
		
		Toast.makeText(mCtx, "cycle:" + cycle, Toast.LENGTH_SHORT).show();
		
		mTVAdpater.setStates(getStates(cycle));
		mTVAdpater.setSelected(true);
		mSpan.setOnTimeViewClikedListener(mOnTVClicked);
		mSpan.setShowMarker(true);
		mTVAdpater.notifyDataChanged();
		
		//int index = mTVAdpater.getCurrent();		
		//int value = mTVAdpater.getValue(index);

		//initDVAdapter(mTVAdpater.getStart());
		//DialViewAdapter dv = mDVAdapters[index];
		DialViewAdapter dv = getDialViewAdapter(mnStep);
		//dv.setPosition(value);
		mDial.setAdpater(dv);
		dv.notifyDataChanged();		

	}
	
	/**step 3*/
	private void showSound()
	{
		mnStep = STEP_SOUND;
		DialViewAdapter dv = getDialViewAdapter(mnStep);
		mDial.setAdpater(dv);
		dv.notifyDataChanged();
		
		mSpan.setOnTimeViewClikedListener(null);
		mSpan.setShowMarker(false);
		mTVAdpater.notifyDataChanged();
	}	
		
	private void step(int step)
	{
		//current is choosing cycle
		if(step == STEP_CYCLE)
		{
			//save cycle
			DialViewAdapter dv = mDial.getAdapter();
			int p = dv.getPosition();
			int cycle = (int)dv.getValue(p);
			mAlarm.setCycle(cycle);
			
			showTimer();
		}
		//current is setting time
		else if(step == STEP_TIME)
		{
			if(!nextTimer())
			{
				Timer t = mTVAdpater.getTimer();
				mAlarm.setTime(t.getTime());
				showSound();
			}
		}
		//current is choosing sound
		else if(step == STEP_SOUND)
		{
			stop();
			cycle().show();
		}
	}
	
	private DialViewAdapter getDialViewAdapter(int step)
	{
		if(step == STEP_CYCLE)
		{
			CycleDVAdpater cdv = new CycleDVAdpater(mCtx);			
			cdv.setPosition(mAlarm.getCycle());
			return cdv;
		}
		else if(step == STEP_TIME)
		{
			return createTimeAdapter();
		}
		else if(step == STEP_SOUND)
		{
			SoundDVAdpater sdv = new SoundDVAdpater(mCtx);
			sdv.setPosition(mAlarm.getSound());
			return sdv;
		}
		return null;
	}
	
	private boolean nextTimer()
	{
		int index = mTVAdpater.getCurrent();
		Timer t = mTVAdpater.getTimer();
		t.set(index, mTVAdpater.getValue(index));
		return updateTimer(index + 1);
	}
	
	private boolean updateTimer(int index)
	{
		if(mTVAdpater.getTotal() <= index || index < 0)
			return false;
		
		mTVAdpater.setCurrent(index);
		mTVAdpater.setSelected(true);
		mTVAdpater.notifyDataChanged();

		ZoneDVAdpater zdv = (ZoneDVAdpater)getDialViewAdapter(mnStep);
		mDial.setAdpater(zdv);
		zdv.notifyDataChanged();
		
		return true;
	}
	
	private int[] getStates(int type)
	{
		switch(type)
		{
		case 0:return new int[]{0,0,0,0,0};			//only once
		case 1:										//every day
		case 2:										//every week
		case 3:return new int[]{-1,-1,-1,0,0};		//every work day
		case 4:										//every month by china
		case 5:return new int[]{-1,-1,0,0,0};		//every month
		case 6:return new int[]{-1,0,0,0,0};		//every year	
		case 7:										//some day of week
		default:return new int[]{-1,-1,-1,0,0};
		}
	}
	
	private DialViewAdapter createTimeAdapter()
	{
		int current = mTVAdpater.getCurrent();
		
		if(!mTVAdpater.isEnable(current))
			return null;	
		Timer t = mTVAdpater.getTimer();
		int position = mTVAdpater.getValue(current);
		return createTimeAdapter(current, t, position);
	}
	
	private DialViewAdapter createTimeAdapter(int index, Timer time, int position)
	{
		int start = 0;
		ZoneDVAdpater zdv = null;
		switch(index)
		{
		case 0: //year
		{
			start = time.get(Timer.YEAR);
			zdv = new ZoneDVAdpater(start, start + 7);
			zdv.setButtonId(R.drawable.time_dial_year);
			zdv.setPosition(position);
			break;
		}
		case 1: //month
		{
			start = 1;
			zdv = new ZoneDVAdpater(start, start + 11);
			zdv.setButtonId(R.drawable.time_dial_moth);
			zdv.setPosition(position);
			break;
		}
		case 2: //date
		{
			start = 1;
			int end = time.getDaysOfMonth() - 1;
			zdv = new ZoneDVAdpater(start, start + end);
			zdv.setButtonId(R.drawable.time_dial_date);
			zdv.setPosition(position);
			break;
		}
		case 3: //hour
		{
			zdv = new ZoneDVAdpater(start, start + 23);
			zdv.setButtonId(R.drawable.time_dial_hour);
			zdv.setPosition(position);
			break;
		}
		case 4: //minute
		{
			zdv= new ZoneDVAdpater(start, start + 59);
			zdv.setButtonId(R.drawable.time_dial_minute);
			zdv.setPosition(position);
			break;
		}
			
		}
		return zdv;
	}
	
	private class MTVClickedListener implements TimeView.OnTimeViewClickedListener
	{
		@Override
		public void onSpanClick(TimeView v, int index) {
			if(mTVAdpater.isEnable(index))
			{
				updateTimer(index);
			}
		}		
	}
	
	private class OnDVClicked implements DialView.OnDialClickListener, DialView.OnDialMarkListener
	{		
		@Override
		public void onClick(View v) {			
			step(mnStep);
		}

		@Override
		public void onMarkChanged(int index) {
			if(mnStep == STEP_CYCLE)
			{
				mAlarm.setCycle(index);
			}
			else if(mnStep == STEP_TIME)
			{
				Timer t = mTVAdpater.getTimer();
				DialViewAdapter dv = mDial.getAdapter();
				
				t.set(mTVAdpater.getCurrent(), (int)dv.getValue(index));
				mAlarm.setTime(t.getTime());
				mTVAdpater.notifyDataChanged();
			}
			else if(mnStep == STEP_SOUND)
			{
				mAlarm.setSound(index);				

				stop();
				mHandler.removeMessages(MSG_PLAYRING);
				mHandler.sendEmptyMessageDelayed(MSG_PLAYRING, 1000);
			}
		}

		@Override
		public void onMarked(int index) {			
		}
	}
	
	
	private class MHandler extends Handler
	{

		@Override
		public void handleMessage(Message msg) {
			if(msg.what == MSG_PLAYRING)
			{
				mRing.play(mAlarm.getSound());
			}
		}
	}
}
